package com.af.security.jwt.filter;

import com.af.security.auth.util.AfAuthenticationUtils;
import com.af.security.jwt.JwtAuthenticationException;
import com.af.security.jwt.token.JwtTokenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author : zhenyun.su
 * @comment :
 * @since : 2020/5/8
 */

public class JwtAuthenticationTokenFilter extends BasicAuthenticationFilter {
    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);

    private JwtTokenService jwtTokenService;
    private String tokenPrefix;
    private AuthenticationSuccessHandler successHandler;
    private AuthenticationFailureHandler failureHandler;


    public JwtAuthenticationTokenFilter(AuthenticationManager authenticationManager, JwtTokenService jwtTokenService,
                                        AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
        super(authenticationManager);
        this.jwtTokenService = jwtTokenService;
        tokenPrefix = jwtTokenService.getTokenPrefix();
        this.successHandler = successHandler;
        this.failureHandler = failureHandler;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        Authentication authentication=null;
        try {
            if (!AfAuthenticationUtils.isAuthAppUrl(request.getRequestURI())){
                chain.doFilter(request, response);
                return;
            }

            String token = jwtTokenService.getTokenValue(request);
            if (StringUtils.isEmpty(token)) {
                logger.error("doFilterInternal, according to http header, not found X3token");
                chain.doFilter(request, response);
                return;
            }
            authentication = jwtTokenService.getAuthentication(token);

            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (AuthenticationException ae) {
            unsuccessfulAuthentication(request,response,ae);
            logger.error("doFilterInternal, exception: {}", ae);
            return;
        } catch (Exception e) {
            unsuccessfulAuthentication(request,response, new JwtAuthenticationException(e.getMessage()));
            logger.error("doFilterInternal, exception: {}", e);
            return;
        };
        chain.doFilter(request, response);
        // this.successfulAuthentication(request, response, chain, authentication);
    }

    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        SecurityContextHolder.clearContext();
        logger.warn(failed.getMessage());
        this.failureHandler.onAuthenticationFailure(request, response, failed);
    }
}
